library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity alu is
    Port ( a : in  STD_LOGIC_VECTOR(7 downto 0);  -- операнд A
           b : in  STD_LOGIC_VECTOR(7 downto 0);  -- операнд B
           ci : in std_logic; -- вход переноса
           op : in  STD_LOGIC_VECTOR(1 downto 0);  -- код операции
           f : out  STD_LOGIC_VECTOR(7 downto 0);  -- результат
           c : out  STD_LOGIC;  -- флаг переноса
           z : out  STD_LOGIC;  -- флаг нуля
           s : out  std_logic; --флаг знака
           mov : in  STD_LOGIC -- флаг перемещения
           );  
end alu;

architecture BEH of alu is
    
    -- функция расчета флагов
function calc_flags(tempfn : SIGNED(8 downto 0); xfn0 : STD_LOGIC_VECTOR(7 downto 0); xfn1 : STD_LOGIC_VECTOR(7 downto 0))
return STD_LOGIC_VECTOR is 
    variable flags : STD_LOGIC_VECTOR(2 downto 0);
begin
    -- флаг переноса
    if tempfn(8) = '1' then
        flags(0) := '1';
    else
        flags(0) := '0';
    end if;
    -- флаг нуля
    if tempfn(7 downto 0) = 0 then
        flags(1) := '1';
    else
        flags(1) := '0';
    end if;
    -- флаг знака
    if (xfn0(7) xor xfn1(7) xor tempfn(8)) = '1' then
        flags(2) := '1';
    else
        flags(2) := '0';
    end if;

    return flags;
end function calc_flags;
--тело АЛУ
begin
    process(a, b, op, ci, mov)
        variable temp : SIGNED(8 downto 0);
        variable b_ext : SIGNED(8 downto 0);
    begin
        -- перемещение операнда A
        if mov = '1' then
            temp := SIGNED('0' & a);
        else
            -- расширение операнда B
            b_ext := SIGNED('0' & b);
            -- выполнение операции
            case op is
                when "00" =>  -- A + B
                    temp := SIGNED('0' & a) + b_ext;
                when "01" =>  -- A - B
                    temp := SIGNED('0' & a) - b_ext;
                when "10" =>  -- A + B + C
                    temp := SIGNED('0' & a) + b_ext + SIGNED(STD_LOGIC_VECTOR(TO_UNSIGNED(0, 8)) & ci);
                                                    
                when "11" =>  -- A - B - C
                    temp := SIGNED('0' & a) - b_ext - SIGNED(STD_LOGIC_VECTOR(TO_UNSIGNED(0, 8)) & ci);
                when others =>
                    temp := (others => '0');
            end case;
        end if;
        
        -- результат и флаги
        f <= STD_LOGIC_VECTOR(temp(7 downto 0));
        c <= calc_flags(temp, a, b)(0);
        z <= calc_flags(temp, a, b)(1);
        s <= calc_flags(temp, a, b)(2);
    end process;
end BEH;